﻿/*************************************************************************
 *     This file & class is part of the Object-Oriented Optimization
 *     Toolbox (or OOOT) Project
 *     Copyright 2010 Matthew Ira Campbell, PhD.
 *
 *     OOOT is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *  
 *     OOOT is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *  
 *     You should have received a copy of the GNU General Public License
 *     along with OOOT.  If not, see <http://www.gnu.org/licenses/>.
 *     
 *     Please find further details and contact information on OOOT
 *     at http://ooot.codeplex.com/.
 *************************************************************************/
using System;
using OptimizationToolbox;

namespace GearSynth.Evaluation
{
    internal class stressConstraint : IInequality
    {
        const int Qv = 9;
        double J = .25;
        //var   J = .30;   //table value? 
        const double Km = 1.6;
        const int Ka = 1;
        const int Ks = 1;
        const int Kb = 1;
        const int Kx = 1;
        double I = 0.1;
        const int Cf = 1;

        private readonly GearTrainAnalysis GTAnalysis;
        private readonly double Nfb, Nfc;

        #region Constructor

        internal stressConstraint(GearTrainAnalysis GTAnalysis, userDefinedGoals udg)
        {
            this.GTAnalysis = GTAnalysis;
            Nfb = udg.Nfb;
            Nfc = udg.Nfc;
        }

        #endregion

        #region Implementation of IOptFunction

        public double calculate(double[] x)
        {
            var gVal = double.NegativeInfinity;
            for (var i = 0; i < GTAnalysis.numGears; i++)
            {
                //var N = x[i*4]; /*number of teeth is not needed, well it could
                /*be used to better estimate J, but simplified here. */

                var pd = x[i * 4 + 1];
                var F = x[i * 4 + 2];
                //var Z = x[i*4 + 3]; position variable is not needed here
                var Wt = GTAnalysis.forces[i];
                var diameter = GTAnalysis.diameters[i];
                var speed = GTAnalysis.speeds[i];
                var Tp = Wt * diameter / 2;
                double fatigue, wear;


                #region 1) calc bending fatique strength
                var Sfb = GTAnalysis.Sfb[i];
                // can eventually put in correction values
                // for life (KL), temperature (KT) and reliability (KR)
                #endregion
                #region 2) calc bending stress
                var B = Math.Pow((12 - Qv), (2 / 3)) / 4;
                var A = 50 + 56 * (1 - B);
                var pitchlineVelocity = speed * (Math.PI / 60) * diameter;
                var Kv = Math.Pow((A / (A + Math.Sqrt(pitchlineVelocity))), B);
                var Ki = 1.0;
                if (GTAnalysis.gearRoles[i].Equals(Role.idler)) Ki = 1.4;
                switch (GTAnalysis.gearTypes[i])
                {
                    case GearType.spur:
                        fatigue = (Wt * pd * Ka * Km * Ks * Kb * Ki) / (F * J * Kv);
                        break;
                    case GearType.bevel:
                        fatigue = (2 * Tp * pd * Ka * Km * Ks) / (diameter * F * J * Kv * Kx);
                        break;
                    default:
                        fatigue = 0;
                        break;
                    // need models for worms, worm gears and helical gears
                }

                #endregion
                gVal = Math.Max(gVal, Nfb * fatigue - Sfb);

                #region 3) calc wear fatigue strength
                var Sfc = GTAnalysis.Sfc[i];
                #endregion

                #region 4) calc wear stress

                var Ca = Ka;
                var Cm = Km;
                var Cv = Kv;
                var Cs = Ks;

                var Cp = 1000;
                // other values from before show Cp = 200, 300, 2000
                // it seems to be based on when mating gears are different
                // material

                switch (GTAnalysis.gearTypes[i])
                {
                    case GearType.spur:
                        wear = Cp * Math.Sqrt(Wt * Ca * Cm * Cs * Cf / (F * I * diameter * Cv));
                        break;
                    case GearType.bevel:
                        J = .21;
                        I = .08;
                        var Cb = .634;
                        var Cmd = 2.4;
                        var Ch = 1;
                        var Cxc = 1;
                        var Ct = 1;
                        var Cr = 1;
                        var Td = (F * I * Cv) / (2 * Cs * Cmd * Cf * Ca * Cxc) * Math.Pow((Sfc * diameter * .774 * Ch / (Cp * Cb * Ct * Cr)), 2);
                        var z = 1.0;
                        if (Tp < Td) z = 0.667;

                        wear = Cp * Cb * Math.Sqrt((2 * Td / (F * I * (Math.Pow(diameter, 2)))) * (Math.Pow((Tp / Td), z)) * Ca * Cm * Cs * Cf * Cxc / Cv);
                        break;
                    default:
                        wear = 0;
                        break;
                        // need models for worms, worm gears and helical gears
                }
                #endregion

                gVal = Math.Max(gVal, Nfc * wear - Sfc);
            }
            return gVal;
        }

        #endregion
    }
}